/*
 ============================================================================
 Name        : sysinfo.c
 Author      : ljf
 Version     :
 Copyright   : Your copyright notice
 Description : API for get linux system inforamtion:cpu, mem, disk usage.
 History     : 2020/01/17 init versoin
 ============================================================================
 */
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/sysinfo.h>
#include<sys/statfs.h>

#include "sysinfo.h"

/*****************************************************************************
	function cal_cpuoccupy()

	arg:
		cpu_occupy_type *o, 	the first timestamp cpu time usage
		cpu_occupy_type *n, 	the second timestamp cpu time usage
		cpu_use_type *cpu_usage	cal the cpu usage

	ret:
		0 :	cal cpu usage OK;
		-1:	cal cpu usage failed;
	
*****************************************************************************/

static int cal_cpuoccupy(cpu_occupy_type *o, cpu_occupy_type *n, cpu_use_type *cpu_usage)
{
	unsigned long total, total_o, total_n;
	unsigned long id, sd;
	cpu_occupy_type dv = {0}; /*used to store the d-value*/
	if(cpu_usage == NULL)
	{
		printf("cpu_usage is null!!\n");
		return -1;
	}
	
	memset(&dv,0x00,sizeof(cpu_occupy_type));
	
	total_o = (unsigned long)(o->user + o->nice + o->system + o->idle + o->wait + o->hardIrq + o->softIrq + o->steal + o->guest);
	total_n = (unsigned long)(n->user + n->nice + n->system + n->idle + n->wait + n->hardIrq + n->softIrq + n->steal + n->guest);
	total = total_n - total_o;

	dv.user = n->user - o->user;
	dv.nice = n->nice - o->nice;
	dv.system = n->system - o->system;
	dv.idle = n->idle - o->idle;
	dv.wait = n->wait - o->wait;
	dv.hardIrq = n->hardIrq - o->hardIrq;
	dv.softIrq = n->softIrq - o->softIrq;
	dv.steal = n->steal - o->steal;
	dv.guest = n->guest - o->guest;
	
	memcpy(cpu_usage->cpuName,o->name,sizeof(o->name));
	cpu_usage->us = (float)(100*(dv.user+dv.nice))/total;
	cpu_usage->sy = (float)(100*(dv.system+dv.hardIrq+dv.softIrq))/total;
	cpu_usage->ni = (float)(100*dv.nice)/total;
	cpu_usage->id = (float)(100*dv.idle)/total;
	cpu_usage->wa = (float)(100*dv.wait)/total;
	cpu_usage->hi = (float)(100*dv.hardIrq)/total;
	cpu_usage->si = (float)(100*dv.softIrq)/total;
	cpu_usage->st = (float)(100*dv.steal)/total;
	#if 0
	printf("%s: %.01f us, %.01f sy, %.01f ni, %.01f id, %.01f wa, %.01f hi, %.01f si, %.01f st\n",
		//"%s: us:%.02f sy:%.02f ni:%.02f id:%.02f wa:%.02f hi:%.02f si:%.02f st:%.02f\n",
			o->name,
			cpu_usage->us,
			cpu_usage->sy,
			cpu_usage->ni,
			cpu_usage->id,
			cpu_usage->wa,
			cpu_usage->hi,
			cpu_usage->si,
			cpu_usage->st);
	#endif
	return 0;
}
/*****************************************************************************
	function get_cpuoccupy()

	arg:
		cpu_occupy_type *cpust

	ret:
		0 :	get cpu info OK;
		-1:	get cpu info failed;
	
*****************************************************************************/
static int get_cpuoccupy(cpu_occupy_type *cpust)
{
	int ret = 0;
	FILE *fd = NULL;
	int n = 0;
	int unsigned long total = 0;
	char buff[256] = {0};
	cpu_occupy_type *cpu_occupy = NULL;
	cpu_occupy_type *o = NULL;
	cpu_occupy = cpust;
	o = cpust;
	fd = fopen(PROC_STAT,"r");
	if(fd == NULL){
		printf("open %s failed!!\n",PROC_STAT);
		return -1;
	}
	fgets(buff, sizeof(buff), fd);
	//printf("get_cpuoccupy 3:buff:%s\n",buff);
	sscanf(buff, "%s %u %u %u %u %u %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice,
				&cpu_occupy->system,&cpu_occupy->idle,&cpu_occupy->wait,&cpu_occupy->hardIrq,
				&cpu_occupy->softIrq,&cpu_occupy->steal,&cpu_occupy->guest);
	total = (unsigned long)(o->user + o->nice + o->system + o->idle + o->wait + o->hardIrq + o->softIrq + o->steal + o->guest);
	#if 0
	printf("name:%s user:%u nice:%u system:%u idle:%u wait:%u hardIrq:%u softIrq:%u steal:%u guest:%u\n", 
			cpu_occupy->name, 
			cpu_occupy->user, 
			cpu_occupy->nice,
            cpu_occupy->system,
            cpu_occupy->idle,
			cpu_occupy->wait,
			cpu_occupy->hardIrq,
			cpu_occupy->softIrq,
			cpu_occupy->steal,
			cpu_occupy->guest
	);
	#endif
	fclose(fd);
	return ret;
}
/*****************************************************************************
	function getCpuUsage()

	arg:
		cpu_use_type *cpu_usage

	ret:
		0 :	get cpu usage OK;
		-1:	get cpu usage failed;
	
*****************************************************************************/
int getCpuUsage(cpu_use_type *cpu_usage)
{
	int ret = 0;
	cpu_occupy_type cpu_stat1;
	cpu_occupy_type cpu_stat2;
	if(cpu_usage == NULL)
	{
		return -1;
	}
	memset(&cpu_stat1,0x00,sizeof(cpu_stat1));
	memset(&cpu_stat2,0x00,sizeof(cpu_stat2));
	memset(cpu_usage,0x00,sizeof(cpu_usage));
	get_cpuoccupy((cpu_occupy_type *)&cpu_stat1);
	sleep(1);
	get_cpuoccupy((cpu_occupy_type *)&cpu_stat2);
	ret = cal_cpuoccupy(&cpu_stat1,&cpu_stat2,cpu_usage);
	//printf("cpu name:%s\n",cpu_usage->cpuName);
	return ret;
}
/*****************************************************************************
	function getMemInfo()

	arg:
		mem_use_type *mem_use

	ret:
		0 :	get mem usage OK;
		-1:	get mem usage failed;
	
*****************************************************************************/
int getMemInfo(mem_use_type *mem_use)
{
	int ret = 0;

	struct sysinfo s = {0};
	if(mem_use == NULL)
	{
		printf("mem_use is NULL!!\n");
		return -1;
	}
	memset(mem_use,0x00,sizeof(mem_use_type));
	
	ret = sysinfo(&s);

	/*Cal the used rate first then trans to KB,MB,GB*/
	
	if(s.totalram != 0)
	{
		mem_use->usedRate = 100.0 - (float)((float)(s.freeram+s.bufferram+s.sharedram)*100/(float)s.totalram);
	}
	
	mem_use->totalram  = STEP_TRANS(s.totalram);
	mem_use->freeram   = STEP_TRANS(s.freeram);
	mem_use->bufferram = STEP_TRANS(s.bufferram);
	mem_use->sharedram = STEP_TRANS(s.sharedram);
		
	return ret;
}
/*****************************************************************************
	function getDiskInfo()

	arg:
		disk_use_type *disk_use

	ret:
		0 :	get disk usage OK;
		-1:	get disk usage failed;
	
*****************************************************************************/
/*
struct statfs { 
   long    f_type;      文件系统类型  
   long    f_bsize;     经过优化的传输块大小 
   long    f_blocks;    文件系统数据块总数 
   long    f_bfree;     可用块数
   long    f_bavail;    非超级用户可获取的块数
   long    f_files;     文件结点总数
   long    f_ffree;     可用文件结点数
   fsid_t  f_fsid;      文件系统标识 
   long    f_namelen;   文件名的最大长度
}; 
*/
int getDiskInfo(disk_use_type *disk_use)
{
	int ret = 0;
	struct statfs diskInfo;
	memset(&diskInfo,0x00,sizeof(diskInfo));
	if(disk_use == NULL)
	{
		printf("disk_use is NULL\n");
		return -1;
	}
	statfs("/etc/vim/vimrc", &diskInfo);
	
	disk_use->diskTotal = diskInfo.f_bsize * diskInfo.f_blocks;
	disk_use->diskAvail = diskInfo.f_bsize * diskInfo.f_bavail;
	/*Cal the used rate first then trans to KB,MB,GB*/
	if(disk_use->diskTotal != 0)
	{
		disk_use->useRate = 100.0 - (float)((float)(disk_use->diskAvail*100)/(float)disk_use->diskTotal);
	}
	
	disk_use->diskTotal = STEP_TRANS(disk_use->diskTotal);
	disk_use->diskAvail = STEP_TRANS(disk_use->diskAvail);
	
	return ret;
}